//
// Created by denglibin on 19-4-11.
//

/**
 * 用户缓冲io：
 * C标准库中提供了标注io库，其中实现了跨平台用户缓冲解决方案。
 *
 * 文件操作：
 *  标准io的函数本质上是 线程安全的，在内部实现中，设置一把锁，一个锁计数器
 *  和为每个打开流创建的所有者线程。一个线程想要执行任何 io请求，必须 首先获得锁而且成为所有者线程。
 *  两个或多个运行在同一流上的线程不能交错地执行io操作，因此在单独一个函数调用的上下文中，标准io操作是原子的。
 *
 *
fgetc和fputc函数：读写一个字符
        fgets和fputs函数:读写一个字符串
        fscanf和fprintf：格式化读写 (新的标准用 fprintf_s)
fwrite和fread是以记录为单位的I/O函数，fread和fwrite函数一般用于二进制文件的输入输出
"r":只读
"w":只写
"a":打开后指向文件末尾,可追加
"rb":打开二进制文件,只读
"wb":打开二进制文件,只写
"ab":打开二进制文件,追加
"r+":以读/写方式打开一个已存在的文件
"w+":以读写建立一个新的文件
"a+":为读写打开一个文本文件进行追加
"rb+"为读写打开一个二进制文件
"wb+":为读写新建一个二进制文件
"ab+":为读写打开一个二进制文件进行追加
 */

#include <stdio.h>
#include <string.h>
#define  PATH "/home/denglibin/open.txt"
#define BUF_SIZE 1024

static void read_c(){
    FILE * file = fopen(PATH, "r");
    if(file == NULL){
        printf("文件打开失败");
        return;
    }
    char buf[BUF_SIZE];
    //feof(file);文件是否到达末尾
    int i = 0;
    while (!feof(file)){
        buf[i++] = fgetc(file); //读取单个字符（内部自己维护了一个缓冲区 4096字节）
    }
    buf[i-1] = '\0'; //结尾
    printf("%s", buf);
    fclose(file); //使用fclose函数就可以把缓冲区内最后剩余的数据输出到磁盘文件中，并释放文件指针和有关的缓冲区。
}
//读取一行
static void read_s(){
    FILE * file = fopen(PATH, "r");
    if(file == NULL){
        printf("文件打开失败");
        return;
    }
    char buf[BUF_SIZE];
    //feof(file);文件是否到达末尾
    /**
     * char * fgets (char *str, int size, FILE *stream);
     * 这个函数从流中读取 size-1个字节的数据，并把数据存入str中。当所有字节读入时，空字符 存入字符串末尾。
     * 当读到EOF或换行符时结束。如果读到换行符，'\n'被写入到str
     */
    while (!feof(file)){
        fgets(buf, BUF_SIZE, file);
        printf("-->%s", buf);
    }
    fclose(file); //使用fclose函数就可以把缓冲区内最后剩余的数据输出到磁盘文件中，并释放文件指针和有关的缓冲区。
}

//写入单个字符
static void write_c(){
    FILE * file = fopen(PATH, "a");
    if(file == NULL){
        printf("文件打开失败");
        return;
    }
    char * s = "中国"; //中文占3个字节
    //feof(file);文件是否到达末尾
    char * p = s;
    while(*p){
        fputc(*p, file); // 内部自己维护了一个缓冲区（4096）
        p++;
    }
    fclose(file); //使用fclose函数就可以把缓冲区内最后剩余的数据输出到磁盘文件中，并释放文件指针和有关的缓冲区。
}
//写入字符串
static void write_s(){
    FILE * file = fopen(PATH, "a");
    if(file == NULL){
        printf("文件打开失败");
        return;
    }
    char * s = "\n中华人民共和国"; //中文占3个字节
    //feof(file);文件是否到达末尾
    fputs(s, file);

    fclose(file); //使用fclose函数就可以把缓冲区内最后剩余的数据输出到磁盘文件中，并释放文件指针和有关的缓冲区。
}

//复制图片
static void copy_pic(){
    char * pic_path = "/home/denglibin/123.jpg";
    char * pic_copy_path = "/home/denglibin/123_copy.jpg";
    FILE * srcFile = fopen(pic_path, "rb");
    if(srcFile == NULL){
        printf("打开原文件失败");
        return;
    }
    FILE * destFile = fopen(pic_copy_path, "wb");
    if(destFile == NULL){
        printf("打开目标文件失败");
        fclose(srcFile);
        return;
    }
    char buf[BUF_SIZE];
    int n;
    while (!feof(srcFile)){
        /**
         * size_t fread (void *buf, size_t size, size_t nr,FILE *stream);
         * 从输入流中读取nr个数据，每个数据有size个字节，并将数据放入buf指向的缓冲区。
         * 返回读入元素的个数（不是子结数）。文件指针向前移动读出数据的长度。
         * 返回 比nr小的数表示失败或文件结束。
         */
       n =  fread(buf, 1, BUF_SIZE, srcFile );
        /**
         * size_t fwrite (void *buf, size_t size, size_t nr, FILE *stream);
         * 把buf指向的nr个元素 写入到stream中，每个元素长度为size,文件指针向前移动写入的所有 字节的长度。
         * 成功时，返回写入的元素的个数（不是字节数），返回小于nr的数表明发发生了错误
         */
       fwrite(buf, 1, n, destFile);
    }
    fclose(srcFile);
    fclose(destFile);

}
static int main_(void){
    //read_s();
    //read_c();
   // write_c();
    //write_s();
    copy_pic();
   return 0;
}
















